Skip to content

Conversation

@brettfo
Copy link
Member

@brettfo brettfo commented May 2, 2018

This completely removes our MSI package and replaces it with new V3 VSIX packages which makes us fully side-by-side compliant.

I tested the following scenarios:

  • Side-by-side install of VS 15.7 and a custom build with these changes.
    • Verified that the compiler files dropped by the 15.7 MSI weren't touched during the test build install.
    • From the 15.7 developer command prompt:
      • %FSHARPINSTALLDIR% = C:\Program Files (x86)\Microsoft SDKs\F#\10.1\Framework\v4.0\ (set by the current MSI)
      • where fsc reports the above location
      • msbuild test.fsproj shows fsc being invoked from that location for both legacy and SDK style projects
      • msbuild reported pulling FSharp.Core.dll from %ProgramFiles(x86)%\Reference Assemblies\....
      • dotnet build uses its own fsc as expected
    • From the test build developer command prompt:
      • %FSHARPINSTALLDIR% = C:\Program Files (x86)\Microsoft Visual Studio\Preview\Enterprise\MSBuild\15.0\Bin\FSharp\ (new location for the VSIX)
      • where fsc reports the above location
      • msbuild test.fsproj shows fsc being invoked from that location for both legacy and SDK style projects
      • msbuild reported pulling FSharp.Core.dll from %VSINSTALLDIR%\MSBuild\15.0\Bin\FSharpSdk thanks to the redirection in Microsoft.FSharp.targets.
      • dotnet build uses its own fsc as expected
    • From VS 15.7:
      • Building a project shows fsc as being invoked from C:\Program Files (x86)\Microsoft SDKs\F#\10.1\Framework\v4.0\ for both desktop and SDK style projects
    • From the test install of VS:
      • Building a project shows fsc as being invoked from C:\Program Files (x86)\Microsoft Visual Studio\Preview\Enterprise\MSBuild\15.0\Bin\FSharp\ for both desktop and SDK style projects
  • Removed VS 15.7 and re-ran all test build scenarios above to ensure nothing was getting pulled from there.
  • Removed everything and installed the BuildTools version with F# support and verified all command line scenarios:
    image

@brettfo brettfo force-pushed the compiler-vsix branch 2 times, most recently from 4a070eb to a6ef545 Compare May 2, 2018 23:06
@abelbraaksma
Copy link
Contributor

Perhaps important to note that it should remain part of VS MSBuild tools. I reported that F# 4.0 is missing there, but new releases should continue to be part of that, I hope, since it's the go to method used on build servers

@brettfo brettfo force-pushed the compiler-vsix branch 7 times, most recently from 1edfc0b to 17e131f Compare May 8, 2018 18:07
@brettfo brettfo changed the title [WIP] move compiler out of MSI and into a VSIX move compiler out of MSI and into a VSIX May 8, 2018
@brettfo
Copy link
Member Author

brettfo commented May 8, 2018

@abelbraaksma I verified the BuildTools scenario with the internal build I generated and it worked as expected. I updated the PR description with all scenarios I tested as well as the checkbox I used for the BuildTools scenario.

@brettfo brettfo force-pushed the compiler-vsix branch 2 times, most recently from 09d3550 to fff1707 Compare May 8, 2018 22:52
@Pilchie
Copy link
Member

Pilchie commented May 8, 2018

@brettfo For the SxS case, does that rely on nothing else changing the MSI? If we have to update something else, won't that mean that the previous builds will stop working when the new MSI is installed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are the above excluded - that doesn't seem right.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The listed files have either already been signed during this build (fsi, etc.) or come from a nuget package (microsoft.build.*).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it be commented somehow so that people know why these are excluded?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly, no. The JSON file format specification doesn't allow comments as per RFC 7159.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had some problems about ngen priority with Roslyn - is this right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll talk to some folks on the compiler team to see what issues they had.

Copy link
Contributor

@KevinRansom KevinRansom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gosh this looks good.

@abelbraaksma
Copy link
Contributor

@brettfo , that sounds great! If there's something specifically you'd want me to test, let me know. I'm traveling, but I'll try to get to it sooner rather than later.

@brettfo brettfo changed the title move compiler out of MSI and into a VSIX remove MSI package and replace with app-local VSIX packages May 10, 2018
@brettfo
Copy link
Member Author

brettfo commented May 10, 2018

I spoke with some internal teams about my initial plan of staging this in two PRs, but the number of potential pitfalls is apparently enormous. I've opted instead to do all of the MSI removal in one PR to keep this atomic.

Copy link
Member

@Pilchie Pilchie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but I'd like someone from MSBuild to sign off, and I'd like to make sure we check with the setup team about both SxS installs and upgrades. Ideally a straight upgrade would remove the old MSI, but SxS installs wouldn't. Not sure if that's possible though.

path is unchanged from the original legacy templates and if a new reference assembly can be found at the new location.
-->
<Target Name="RedirectFSharpCoreReferenceToNewRedistributableLocation" BeforeTargets="ResolveAssemblyReferences">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how I feel about this target. It's very clever, but may also be very surprising to people, and I feel like various bits of tooling that only use the evaluated MSBuild model will be wrong because they will still use the old hint path.

With that said, I'm not sure of anything better :-/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the best we could come up with for not breaking legacy projects, but still removing the MSI from the install toolchain (which unfortunately means we can't have a global, well-known location.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. What did the old templates put in user proj files?

Does this do the right thing in design-time builds?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't see any issues with design time builds, but I'll do another pass checking for this specifically.

The old templates created the project files like this:

<ItemGroup>
  ...
  <Reference Include="FSharp.Core">
    <Name>FSharp.Core</Name>
    <AssemblyName>FSharp.Core.dll</AssemblyName>
    <HintPath>$(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\$(TargetFSharpCoreVersion)\FSharp.Core.dll</HintPath>
  </Reference>
  ...
</ItemGroup>

and we want to make sure we don't break those scenarios.

version=$(FSharpPackageVersion)

folder "InstallDir:Common7\IDE\CommonExtensions\Microsoft\FSharpSdk"
folder "InstallDir:MSBuild\15.0\Bin\FSharpSdk"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rainersigwald - is this the right sort of convention here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied the Roslyn behavior for this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not expect F# to need to be in the MSBuild bin folder. C# is special because we both used to be in the framework. Plus, people often construct relative paths, so changing it can break folks. Did something break with the old path?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original location from the MSI was C:\Program Files (x86)\Microsoft SDKs\FSharp\.... My first round of this PR moved the compiler to Common7\IDE\CommonExtensions\Microsoft\FSharpSdk, but that felt wrong for the BuildTools SKU because there is no IDE. The second round of this PR I moved it to be under MSBuild to copy C#. Do you have a suggestion for a better place to put it?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would agree with @rainersigwald. I don't this this is an acceptable location, especially given that you're redistributing our old binaries. Common7\IDE\CommonExtensions\Microsoft\FSharpSdk seems fine with me, that's where NuGet is and they're required in no-IDE scenarios.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<Import Project="$(MSBuildThisFileDirectory)..\..\..\..\..\Common7\IDE\CommonExtensions\Microsoft\FSharpCompiler\Microsoft.FSharp.NetSdk.props" />
<Import Project="$(VsInstallRoot)\MSBuild\15.0\Bin\FSharp\Microsoft.FSharp.NetSdk.props" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can VsInstallRoot be counted on to exist?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to this that value will always be present, but reading the comment it could behave oddly with $(PlatformToolset). Would you prefer I go back to the $(MSBuildThisFileDirectory)..\..\..\etc method? It doesn't look as clean, but will always produce consistent results.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PlatformToolset is a pretty C++ concept, so I'm not too worried about that. However, I do wonder about things like the build sku. I'll defer to @rainersigwald or @AndyGerlicher for what should happen here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also tested on a clean machine with only the BuildTools version installed. Running msbuild MyProject.fsproj showed the correct compiler and FSharp.Core being used which means these targets redirected appropriately.

@brettfo
Copy link
Member Author

brettfo commented May 11, 2018

@Pilchie Regarding your comment about SxS installs, I verified that I could install/uninstall 15.7 and my custom build in any order. 15.7 always removed the MSI when it was uninstalled, but that never interfered with my custom build. From the internal email conversation I gathered that upgrade would trigger an uninstall.

@Pilchie
Copy link
Member

Pilchie commented May 11, 2018

I inferred that upgrade would trigger an uninstall/reinstall if the new version contains the MSI, but what happens if the new version doesn't?

Would a straight uninstall be a problem if someone upgrades Preview channel from P2 (with MSI) to P3 (without MSI), while also having 15.7 installed, or would ref-counting deal with that.

I think things should work out, but I think we have some more testing to consider - or at least thought experiments involving people who know more about setup than me :)

@brettfo
Copy link
Member Author

brettfo commented May 11, 2018

It appears our existing MSI is properly ref-counted so the scenario of having multiple instances installed and upgrading one of them (which will in turn /uninstall the MSI) should work. I simulated this by checking the following:

  1. Verify no F# SDK is installed via Get-WmiObject -Class win32_product | Where-Object ($_.Name -Match ".*F#.*"}.
  2. Install 15.7 Community => 1 copy of the SDK is installed as per step 0.
  3. Install 15.7 Enterprise => still 1 copy of the SDK, e.g., a duplicate copy wasn't installed.
  4. Uninstall 15.7 Community => still 1 copy of the SDK, e.g., it wasn't removed even though the corresponding install is what initially put it there.
  5. Uninstall 15.7 Enterprise => 0 copies of the SDK.

@brettfo
Copy link
Member Author

brettfo commented May 14, 2018

@Pilchie, did you have any other questions regarding this PR? I think I covered your issues above, although maybe not with enough depth.

@Pilchie
Copy link
Member

Pilchie commented May 14, 2018

LGTM, but I would feel more comfortable if we can get someone from the setup team to take a look, and would really like @rainersigwald, or another MSBuild dev to take a look too.

Copy link
Member

@rainersigwald rainersigwald left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving into the MSBuild folder is my biggest concern.

file source="$(BinariesFolder)\net40\bin\fsiAnyCpu.exe.config"
file source="$(BinariesFolder)\net40\bin\Microsoft.Build.Conversion.Core.dll"
file source="$(BinariesFolder)\net40\bin\Microsoft.Build.dll"
file source="$(BinariesFolder)\net40\bin\Microsoft.Build.Engine.dll"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you redistributing MSBuild assemblies?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Our current MSI ships these, too. If you have F# installed on your machine these assemblies live next to our compiler at C:\Program Files (x86)\Microsoft SDKs\F#\10.1\Framework\v4.0.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rainersigwald. Unfortunately yes. The F# compiler needs this, it's something we are going to try to eliminate eventually, but it's not going to happen quickly.


<ItemGroup>
<!-- Update references to `.NETCore\*\FSharp.Core.dll`. -->
<Reference Update="%(Reference.Identity)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use Update= inside a target . . . it doesn't do the right thing. dotnet/msbuild#2835

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate? I read the attached issue, but wasn't able to follow. In my testing the Update= seemed to do the right thing; the <HintPath> for FSharp.Core was appropriately redirected.

path is unchanged from the original legacy templates and if a new reference assembly can be found at the new location.
-->
<Target Name="RedirectFSharpCoreReferenceToNewRedistributableLocation" BeforeTargets="ResolveAssemblyReferences">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. What did the old templates put in user proj files?

Does this do the right thing in design-time builds?

<ItemGroup>
<!-- Update references to `.NETCore\*\FSharp.Core.dll`. -->
<Reference Update="%(Reference.Identity)"
Condition="'%(Reference.Identity)' == 'FSharp.Core' and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it matter if this misses references that were referenced by full assembly identity?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These updates are only to catch project files that never changed the default values, and the F# templates (to my knowledge) have never used the full assembly identity. If a developer modifies this value then they're on their own for locating FSharp.Core.

@AndyGerlicher
Copy link

I really wish this could be moved to a NuGet package or MSBuild SDK that could just be acquired a build-time (or local offline feed) :(

I realize that would likely change project files to work though so it might be out. At minimum though, this shouldn't go under MSBuild bin folder. $(MSBuildExtensionsPath) is the legacy style location for finding stuff that VS magically lays out on your machine, so if you can't go with something outside of MSBuild's folder I would key off of that. Maybe $(MSBuildExtensionsPath)\Microsoft\FSharp\?

@brettfo brettfo force-pushed the compiler-vsix branch 2 times, most recently from 992b6c1 to f77094b Compare May 16, 2018 17:40
@brettfo
Copy link
Member Author

brettfo commented May 16, 2018

I've changed the location of the F# compiler back to InstallDir:Common7\IDE\CommonExtensions\Microsoft\FSharpCompiler and updated the shim targets to use this exact path instead of a relative path.

@brettfo
Copy link
Member Author

brettfo commented May 17, 2018

@AndyGerlicher @rainersigwald I've moved the compiler to InstallDir:Common7\IDE\CommonExtensions\Microsoft\FSharpCompiler. Did either of you have any other concerns?

@cartermp cartermp added this to the 15.8 milestone May 20, 2018
@brettfo
Copy link
Member Author

brettfo commented May 23, 2018

Ping to @rainersigwald. You mentioned above that Update= shouldn't be used in a target, can you tell me why? I wasn't able to discern the problem via the link you originally provided. In my local testing the Update= calls executed in the target without issue and the references were appropriately redirected. I verified this by setting the build output to Normal and Ctrl+Shift+B and verifying the reference passed to fsc.exe in the output window.

@rainersigwald
Copy link
Member

Ah, sorry. Update shouldn't be used in an item in a target because it is ignored. It can work in some cases if you're not actually attempting to update a subset of uses, but you shouldn't rely on that; we'd like to make it an error in the future.

@brettfo
Copy link
Member Author

brettfo commented May 23, 2018

Update doesn't work in a target, but can I use Include and Remove? Or are those a similar mechanism/also ignored?

@rainersigwald
Copy link
Member

rainersigwald commented May 24, 2018 via email

@brettfo
Copy link
Member Author

brettfo commented May 24, 2018

@rainersigwald I re-worked Microsoft.FSharp.targets to use only Remove and Include instead of Update, can you take another peek at it? If it makes the diff easier it's the most recent commit on this PR.

Edit, I spoke with Rainer offline and it turns out I just need to remove the Update= lines from the target.

@brettfo
Copy link
Member Author

brettfo commented May 25, 2018

Final validation build (with removed Update= attributes) shows that references are getting rewritten as expected. Last call for any final comments, I'll leave this open for a few hours.

@brettfo brettfo merged commit 958bfea into master May 25, 2018
@brettfo brettfo deleted the compiler-vsix branch May 25, 2018 21:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants